package tang.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

/**
 * @author Tang
 * @classname NioServerCnxnFactory
 * @description [ 处理io读写 ]
 * @date 2021/2/28 21:11
 */
public class NioServerCnxnFactory implements Runnable{

    private InetSocketAddress inetSocketAddress;
    private ServerSocketChannel ss;
    private Selector selector;
    private ZkThread thread;
    private ZkServer zks;


    public NioServerCnxnFactory() throws IOException {
        this.selector = Selector.open();
    }

    public void configure(InetSocketAddress address) {
        this.inetSocketAddress = address;
        try {
            // 初始化 server
            this.ss = ServerSocketChannel.open();
            this.ss.socket().setReuseAddress(true);
            this.ss.socket().bind(inetSocketAddress);
            this.ss.configureBlocking(false);
            this.ss.register(this.selector, SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 设置当前线程信息
        thread = new ZkThread(this, "NioServerCnxnFactory-thread");
        thread.setDaemon(true);
    }

    public void startUp(ZkServer zks) {
        // 当前启动线程
        start();

        setZkServer(zks);

        // 初始化db数据库
        zks.startdata();

        // 初始化链式处理器
        zks.startup();
    }

    @Override
    public void run() {
        while (true) {
            try {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                selectionKeys.forEach(selectionKey -> {
                    // 连接请求
                    if ((selectionKey.readyOps() & SelectionKey.OP_ACCEPT) != 0) {
                        SocketChannel socketChannel = null;
                        try {
                            socketChannel = this.ss.accept();
                            socketChannel.configureBlocking(false);
                            socketChannel.register(this.selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
                            // attach 一个对象
                            selectionKey.attach(new NIOServerCnxn(this.zks, selectionKey, socketChannel));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        // 读写请求
                    } else if ((selectionKey.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {
                        NIOServerCnxn nioServerCnxn = (NIOServerCnxn)selectionKey.attachment();
                        // 处理
                        nioServerCnxn.doIO(selectionKey);
                    }
                });
                selectionKeys.clear();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void setZkServer(ZkServer zks) {
        this.zks = zks;
        zks.registerNioServerCnxnFactory(this);
    }

    private void start() {
        if (thread != null) {
            thread.start();
        }
    }

    public void shutdown() {
        if (thread != null) {

        }
    }

    public void join() {

    }
}